package algos;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.PathIterator;

public class Isovist {

    public Shape Perimeter;
    public Area perimArea;
    public Point P;
    private final int NUM_RAYES = 360;
    public Point[] rays = new Point[NUM_RAYES * 2];
    public Polygon polygon = new Polygon();

    public Isovist(Area perim) {
        perimArea = (Area) perim.clone();
        Perimeter = (Shape) perim.clone();
    }

    public void returnToDefault() {
        Perimeter = (Shape) perimArea.clone();
    }

    public void createHoles(Shape[] holes) {
        Area temp = (Area) perimArea.clone();
        for (int i = 0; i < holes.length; i++) {
            Area a = new Area(holes[i]);
            temp.subtract(a);
        }
        Perimeter = temp;
    }

    public Isovist(Shape perim, Point pt) {
        Perimeter = perim;
        P = pt;
        doIso(P);
    }

    public void doIso(Point pt) {
        P = pt;
        double xt, yt, mx, my;
        double x1, x2, x3, x4, y1, y2, y3, y4;
        double[] coords = {0., 0., 0., 0., 0., 0.};
        PathIterator pit = Perimeter.getPathIterator(null);
        int j = 0;
        for (int i = 0; i < NUM_RAYES; i++) {
            xt = (P.x + 1000.0d * Math.sin(Math.toRadians((double) i)));
            yt = (P.y + 1000.0d * Math.cos(Math.toRadians((double) i)));

            x1 = P.getX();
            y1 = P.getY();

            double u12, u34, t;
            pit = Perimeter.getPathIterator(null);

            x3 = 0.;
            x4 = 0.;
            y3 = 0.;
            y4 = 0.;
            mx = 0.;
            my = 0.;
            boolean ok = false;

            while (!pit.isDone()) {
                x2 = xt;
                y2 = yt;

                if (pit.currentSegment(coords) == PathIterator.SEG_MOVETO) {
                    mx = coords[0];
                    my = coords[1];
                    x3 = mx;
                    y3 = my;
                    ok = false;
                } else if (pit.currentSegment(coords) == PathIterator.SEG_LINETO) {
                    x4 = coords[0];
                    y4 = coords[1];
                    ok = true;
                } else if (pit.currentSegment(coords) == PathIterator.SEG_CLOSE) {
                    x4 = mx;
                    y4 = my;
                    ok = true;
                }

                // * segment intersection calculation adapted from http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
                if (ok) {
                    t = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
                    if (t != 0.0d) {
                        u12 = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / t;
                        u34 = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / t;
                        if ((u34 > 0.0d && u34 < 1.0d) && (u12 > 0.0d && u12 < 1.0d)) {  //intersects boundary segment
                            xt = x1 + u12 * (x2 - x1);
                            yt = y1 + u12 * (y2 - y1);
                            //System.out.println(" ray "+i+" ("+xt+","+yt+")"+u34);
                        }
                    }
                    x3 = x4;
                    y3 = y4;
                }
                pit.next();
            }

            rays[j] = new Point((int) xt, (int) yt);
            j++;
            //System.out.println(" ray "+i+" ("+xt+","+yt+")");
        }
        int[] xpoints = new int[rays.length];
        int[] ypoints = new int[rays.length];

        for (int i = 0; i < NUM_RAYES; i++) {
            xpoints[i] = rays[i].x;
            ypoints[i] = rays[i].y;
//			System.out.println(i);
        }
        polygon.xpoints = xpoints;
        polygon.ypoints = ypoints;
        polygon.npoints = NUM_RAYES;
    }

    public void paint(Graphics2D g2d) {
        g2d.setColor(Color.red);
        g2d.draw(Perimeter);
        int[] xpoints = new int[rays.length];
        int[] ypoints = new int[rays.length];

        for (int i = 0; i < NUM_RAYES; i++) {
            xpoints[i] = rays[i].x;
            ypoints[i] = rays[i].y;
        }
        polygon.xpoints = xpoints;
        polygon.ypoints = ypoints;
        polygon.npoints = NUM_RAYES;
        g2d.setColor(Color.yellow);
        g2d.fill(polygon);
        g2d.drawPolygon(polygon);
    }
}
